package com.ruoyi.web.utils;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author yxc
 * @Title: DateUtils
 * @Description: 时间处理工具类
 */
@Slf4j
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

    /**
     * 系统数据库默认时间的毫秒值（1900-01-01 00:00:00）
     */
    private static final Long DEFAULT_DATE = -2209017600000L;


    /**
     * 获取两个日期之间的所有日期集合
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<String> splitDateList(Date startDate, Date endDate, String pattern) {
        List<String> listDate = new ArrayList<>();
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            while (calendar.getTime().before(endDate) || calendar.getTime().equals(endDate)) {
                listDate.add(dateFormat.format(calendar.getTime()));
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
            return listDate;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listDate;
    }

    /**
     * 英文时间转换成中文时间
     *
     * @param dataStr 字符串时间
     * @return
     */
    public static Date englishToChina(String dataStr) {
        Date date = null;
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH);
            date = dateFormat.parse(dataStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 时间转换成毫秒
     *
     * @param dataStr 字符串时间
     * @return
     */
    public static long string2TimeMillis(String dataStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        try {
            return sdf.parse(dataStr).getTime();
        } catch (ParseException e) {
            log.error("时间格式转换错误:{}", dataStr);
            return 0L;
        }
    }

    /**
     * 将长时间格式时间转换为字符串 yyyy-MM-dd HH:mm:ss
     *
     * @param dateDate
     * @return
     */
    public static String dateToStrLong(Date dateDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    public static Date stringToDate(String dateDate) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date dateString = formatter.parse(dateDate);
        return dateString;
    }

    /**
     * 获取今天的开始时间
     *
     * @return 开始时间 yyyy-MM-dd HH:mm:ss
     */
    public static Date todayStartTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取今天的结束时间
     *
     * @return 结束时间 yyyy-MM-dd HH:mm:ss
     */
    public static Date todayEndTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    /**
     * 比较传入的两个日期差值与目标差值大小
     *
     * @param before   相对早的日期
     * @param after    相对晚的日期
     * @param timeNum  时间值大小
     * @param timeUnit 时间单位 seconds -> days
     * @return -1 小于目标值 0 等于目标值 1 大于目标值
     */
    public static int compareTimeDiffWithTargetTimeDiff(Date before, Date after, Integer timeNum, TimeUnit timeUnit) {
        if (before == null || after == null || before.compareTo(after) > 0) {
            throw new IllegalArgumentException("param is illegitimate");
        }
        long afterTimestamp = after.getTime();
        long beforeTimestamp = before.getTime();
        long diffTimestamp = afterTimestamp - beforeTimestamp;
        if (diffTimestamp < 0) {
            diffTimestamp = -diffTimestamp;
        }
        switch (timeUnit) {
            case SECONDS:
                return Long.compare(diffTimestamp, timeNum * 1000L);
            case MINUTES:
                return Long.compare(diffTimestamp, timeNum * 1000L * 60);
            case HOURS:
                return Long.compare(diffTimestamp, timeNum * 1000L * 60 * 60);
            case DAYS:
                return Long.compare(diffTimestamp, 1000L * 60 * 60 * 24 * timeNum);
            default:
                throw new IllegalArgumentException("param is illegitimate");
        }
    }

    /**
     * 通过时间秒毫秒数判断两个时间的间隔
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    /**
     * 计算两个时间的间隔（秒）
     *
     * @param date1 减数
     * @param date2 被减数
     * @return
     */
    public static int differentSecondsByMillisecond(Date date1, Date date2) {
        int seconds = (int) ((date2.getTime() - date1.getTime()) / 1000);
        return seconds;
    }

    /**
     * 计算两个时间的间隔（分钟）
     *
     * @param date1 减数
     * @param date2 被减数
     * @return
     */
    public static int differentMinutesByMillisecond(Date date1, Date date2) {
        int minutes = (int) ((date2.getTime() - date1.getTime()) / (1000 * 60));
        return minutes;
    }

    /**
     * 获取当前时间
     *
     * @param @return
     * @param @throws Exception 参数
     * @return Date 返回类型
     */
    public static Date getLocalDateTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        return localDateTimeToDate(localDateTime);
    }

    /**
     * LocalDateTime转换为Date
     *
     * @param @param  localDateTime
     * @param @return 参数
     * @return Date 返回类型
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        Date date = Date.from(zonedDateTime.toInstant());
        return date;
    }

    /**
     * Date转换为LocalDateTime
     *
     * @param @param  date
     * @param @return 参数
     * @return LocalDateTime 返回类型
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    /**
     * 获取本月的开始时间
     *
     * @return
     */
    public static Date getMonthStartTime() {
        Calendar dateStart = Calendar.getInstance();
        dateStart.add(Calendar.MONTH, 0);
        dateStart.set(Calendar.DAY_OF_MONTH, 1);
        return dateStart.getTime();
    }

    /**
     * 获取本月结束时间
     *
     * @return
     */
    public static Date getMonthEndTime() {
        Calendar dateEnd = Calendar.getInstance();
        dateEnd.add(Calendar.MONTH, 1);
        dateEnd.set(Calendar.DAY_OF_MONTH, 0);
        return dateEnd.getTime();
    }


    /**
     * 判断日期是不是当天
     *
     * @param date
     * @return
     */
    public static boolean isToday(Date date) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = format.format(date);
            String today = format.format(new Date());
            return Objects.equals(dateStr, today);
        }
        return false;
    }


    /**
     * 判断日期是不是某天
     *
     * @param date
     * @return
     */
    public static boolean isoneDay(Date date, Date oneDay) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String dateStr = format.format(date);
            String today = format.format(oneDay);
            return Objects.equals(dateStr, today);
        }
        return false;
    }


    public static Date stringToDate(String strTime, String formatType) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat(formatType);
        Date date = null;
        date = formatter.parse(strTime);
        return date;
    }

    public static int getAge(Date birthDay) {
        if (birthDay == null || birthDay.getTime() == -2209017600000L) {
            return 0;
        }
        Date now = new Date();
        if (now.before(birthDay)) {
            return 0;
        }
        LocalDate nowLocalDate = now.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate birthdayLocalDate = birthDay.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        Period period = Period.between(birthdayLocalDate, nowLocalDate);
        return period.getYears();
    }

    // 获取昨天的开始时间
    public static Date getBeginDayOfYesterday() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(todayStartTime());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    // 获取昨天的结束时间
    public static Date getEndDayOfYesterDay() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(todayEndTime());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }


    /**
     * 获取本周开始时间
     *
     * @return
     */
    public static Date getBeginDayOfWeek() {
        Calendar cal = Calendar.getInstance();
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek);
        return getDayStartTime(cal.getTime());
    }

    // 获取本周的结束时间
    public static Date getEndDayOfWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    /**
     * 获取上周的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfLastWeek() {
        Calendar cal = Calendar.getInstance();
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek - 7);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取上周的结束时间
     *
     * @return
     */
    public static Date getEndDayOfLastWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfLastWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    // 获取上月的开始时间
    public static Date getBeginDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        return getDayStartTime(calendar.getTime());
    }

    // 获取上月的结束时间
    public static Date getEndDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);
        return getDayEndTime(calendar.getTime());
    }


    /**
     * 获取某个时间的开始时间
     *
     * @return 开始时间 yyyy-MM-dd HH:mm:ss
     */
    public static Date getDayStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    public static Date getDaySixTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 6);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取某个时间的结束时间
     *
     * @return 开始时间 yyyy-MM-dd HH:mm:ss
     */
    public static Date getDayEndTime(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }

    // 获取今年是哪一年
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(1);
    }

    // 获取本月是哪一月
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    // 获取上月是哪一月
    public static int getUpperMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2);
    }

    //获取几天前/后的时间
    public static Date getLaterDate(Date date, int num) {
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date);
        calendar2.add(Calendar.DATE, num);
        return calendar2.getTime();
    }

    // 获取某个时间的年
    public static int getDateYear(Date date) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        return calendar.get(Calendar.YEAR);
    }

    // 获取某个时间的小时数
    public static int getDateHour(Date date) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    // 获取默认时间（1900-01-01 00:00:00）
    public static Date getDefaultDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, 1900);
        calendar.set(Calendar.MONTH, Calendar.JANUARY);
        calendar.set(Calendar.DATE, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 是否为默认日期时间:1900-01-01 00:00:00
     *
     * @param @param  datetime
     * @param @return 参数
     * @return Boolean 返回类型
     */
    public static boolean isDefaultDate(Date datetime) {
        if (datetime == null) {
            return false;
        }
        long time = datetime.getTime();
        return DEFAULT_DATE.equals(time);
    }

    public static String getCurrentDayStr() {
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        return format.format(new Date());
    }

    /**
     * 获取格式化日期：yyyy-MM-dd
     *
     * @param date 时间
     * @return java.lang.String
     */
    public static String getFormatDate(Date date) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String localDate = format.format(date);
        return localDate;
    }

    /**
     * 获取当前日期是星期几
     *
     * @param date
     * @return 当前日期是星期几 - 例 1 - 周一, 7 - 周日
     */
    public static Integer getWeekOfDate(Date date) {
        Integer[] weekDays = {7, 1, 2, 3, 4, 5, 6};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) {
            w = 0;
        }
        return weekDays[w];
    }

    public static Date selectMinOffer(Date nowDate, long time) {
        Date beforeDate = new Date(nowDate.getTime() - time * 60 * 1000);//30分钟前的时间
        return beforeDate;
    }

    /**
     * 获取n小时之后的时间
     *
     * @param date
     * @param time 小时
     * @return
     */
    public static String queryHoursAfter(Date date, int time) {
        LocalDateTime currentDateTime = dateToLocalDateTime(date);
        // 添加8小时
        LocalDateTime eightHoursLater = currentDateTime.plusHours(time);
        // 格式化输出
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedEightHoursLater = eightHoursLater.format(formatter);
        return formattedEightHoursLater;
    }

    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致
     *
     * @param nowTime   当前时间
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        return date.after(begin) && date.before(end);
    }

    /**
     * 获取当前时间距离一天结束的剩余秒数
     *
     * @param currentDate 当前时间
     * @return 剩余秒数
     */
    public static Integer getRemainSecondsOneDay(Date currentDate) {
        LocalDateTime midnight = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault()).plusDays(1).withHour(0).withMinute(0)
                .withSecond(0).withNano(0);
        LocalDateTime currentDateTime = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault());
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        return (int) seconds;
    }


    /**
     * 获取过去第几天的日期
     *
     * @param past
     * @return
     */
    public static Date getPastDate(int past, Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - past);
        return calendar.getTime();
    }

    public static String getStringDate(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(date);
    }

    /**
     * 获取某个时间的只包含年月日的时间
     *
     * @param date 时间参数
     * @return 只包含年月日的时间
     */
    public static Date getDate(Date date) {
        if (date == null) {
            return null;
        }
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.set(Calendar.HOUR_OF_DAY, 0);
        instance.set(Calendar.MINUTE, 0);
        instance.set(Calendar.SECOND, 0);
        return instance.getTime();
    }

    /**
     * 获取几分钟后的时间
     *
     * @param date    时间
     * @param minutes 分钟数
     * @return java.util.Date
     */
    public static Date addDateForMinutes(Date date, int minutes) {
        if (date == null) {
            return null;
        }
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(Calendar.MINUTE, minutes);
        return instance.getTime();
    }

    /**
     * 将长时间格式时间转换为字符串 yyyy-MM-dd HH:mm:ss
     *
     * @param dateDate
     * @return
     */
    public static String dateToString(Date dateDate) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    public static String longToString(long timestamp) {
        Date date = new Date(timestamp);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String formattedDate = sdf.format(date);
        return formattedDate;
    }

    public static String dateToString(Date dateDate, String pattern) {
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    /**
     * 只获取时间的年月日
     *
     * @param date 带时分秒的时间
     * @return
     */
    public static Date getDayDate(Date date) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.parse(calendar.get(Calendar.YEAR) + "-" + calendar.get(Calendar.MONTH) + "-" + calendar.get(Calendar.DATE));
    }

    /**
     * 获取起时和结束时间中间的时间
     *
     * @param start 起时时间
     * @param end   结束时间
     * @return 中间时间
     */
    public static Date getDateMiddle(Date start, Date end) {
        return new Date(((end.getTime() - start.getTime()) / 2) + start.getTime());
    }

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str)
    {
        if (str == null)
        {
            return null;
        }
        try
        {
            return parseDate(str.toString(), parsePatterns);
        }
        catch (ParseException e)
        {
            return null;
        }
    }

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static final String dateTimeNow(final String format)
    {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date)
    {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date)
    {
        return new SimpleDateFormat(format).format(date);
    }

}